﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Colors;
using System.Reflection;

namespace WCAD
{
    public class PropertyChangerCmds

    {

        [CommandMethod("TEST")]

        public void TestInput()

        {

            Document doc =

              Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;


            System.Type objType;

            string propName;

            object newPropValue;

            bool recurse;


            if (SelectClassPropertyAndValue(

                  out objType,

                  out propName,

                  out newPropValue,

                  out recurse

                )

              )

            {

                ed.WriteMessage(

                  "\nType selected: " + objType.Name +

                  "\nProperty selected: " + propName +

                  "\nValue selected: " + newPropValue +

                  "\nRecurse chosen: " + recurse

                );

            }

            else

            {

                ed.WriteMessage(

                  "\nFunction returned false."

                );

            }

        }


        private bool SelectClassPropertyAndValue(

          out System.Type objType,

          out string propName,

          out object newPropValue,

          out bool recurse)

        {

            Document doc =

              Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;


            objType = null;

            propName = "";

            newPropValue = null;

            recurse = true;


            // Let's first get the class to query for

            PromptResult ps =

              ed.GetString(

                "\nEnter type of objects to look for: "

              );


            if (ps.Status == PromptStatus.OK)

            {

                string typeName = ps.StringResult;


                // Use reflection to get the type from the string

                objType =

                  System.Type.GetType(

                    typeName,

                    false,        // Do not throw an exception

                    true          // Case-insensitive search

                  );


                // If we didn't find it, try prefixing with

                // "Autodesk.AutoCAD.DatabaseServices."


                if (objType == null)

                {

                    objType =

                      System.Type.GetType(

                        "Autodesk.AutoCAD.DatabaseServices." +

                        typeName + ", acdbmgd",

                        false,      // Do not throw an exception

                        true        // Case-insensitive search

                      );

                }


                if (objType == null)

                {

                    ed.WriteMessage(

                      "\nType " + typeName + " not found."

                    );

                }

                else

                {

                    // If we have a valid type then let's

                    // first list its writable properties

                    ListProperties(objType);


                    // Prompt for a property

                    ps = ed.GetString(

                      "\nEnter property to modify: "

                    );


                    if (ps.Status == PromptStatus.OK)

                    {

                        propName = ps.StringResult;


                        // Make sure the property exists...

                        System.Reflection.PropertyInfo propInfo =

                          objType.GetProperty(propName);

                        if (propInfo == null)

                        {

                            ed.WriteMessage(

                              "\nProperty " +

                              propName +

                              " for type " +

                              typeName +

                              " not found."

                            );

                        }

                        else

                        {

                            if (!propInfo.CanWrite)

                            {

                                ed.WriteMessage(

                                  "\nProperty " +

                                  propName +

                                  " of type " +

                                  typeName +

                                  " is not writable."

                                );

                            }

                            else

                            {

                                // If the property is writable...

                                // ask for the new value

                                System.Type propType = propInfo.PropertyType;

                                string prompt =

                                      "\nEnter new value of " +

                                      propName +

                                      " property for all objects of type " +

                                      typeName +

                                      ": ";


                                // Only certain property types are currently

                                // supported: Int32, Double, String, Boolean

                                switch (propType.ToString())

                                {

                                    case "System.Int32":

                                        PromptIntegerResult pir =

                                          ed.GetInteger(prompt);

                                        if (pir.Status == PromptStatus.OK)

                                            newPropValue = pir.Value;

                                        break;

                                    case "System.Double":

                                        PromptDoubleResult pdr =

                                          ed.GetDouble(prompt);

                                        if (pdr.Status == PromptStatus.OK)

                                            newPropValue = pdr.Value;

                                        break;

                                    case "System.String":

                                        PromptResult psr =

                                          ed.GetString(prompt);

                                        if (psr.Status == PromptStatus.OK)

                                            newPropValue = psr.StringResult;

                                        break;

                                    case "System.Boolean":

                                        PromptKeywordOptions pko =

                                          new PromptKeywordOptions(

                                          prompt);

                                        pko.Keywords.Add("True");

                                        pko.Keywords.Add("False");

                                        PromptResult pkr =

                                          ed.GetKeywords(pko);

                                        if (pkr.Status == PromptStatus.OK)

                                        {

                                            if (pkr.StringResult == "True")

                                                newPropValue = true;

                                            else

                                                newPropValue = false;

                                        }

                                        break;

                                    default:

                                        ed.WriteMessage(

                                          "\nProperties of type " +

                                          propType.ToString() +

                                          " are not currently supported."

                                        );

                                        break;

                                }

                                if (newPropValue != null)

                                {

                                    PromptKeywordOptions pko =

                                      new PromptKeywordOptions(

                                        "\nChange properties in nested blocks: "

                                      );

                                    pko.AllowNone = true;

                                    pko.Keywords.Add("Yes");

                                    pko.Keywords.Add("No");

                                    pko.Keywords.Default = "Yes";

                                    PromptResult pkr =

                                      ed.GetKeywords(pko);

                                    if (pkr.Status == PromptStatus.None |

                                        pkr.Status == PromptStatus.OK)

                                    {

                                        if (pkr.Status == PromptStatus.None |

                                            pkr.StringResult == "Yes")

                                            recurse = true;

                                        else

                                            recurse = false;


                                        return true;

                                    }

                                }

                            }

                        }

                    }

                }

            }

            return false;

        }


        private void ListProperties(System.Type objType)

        {

            Document doc =

              Application.DocumentManager.MdiActiveDocument;

            Editor ed = doc.Editor;


            ed.WriteMessage(

              "\nWritable properties for " +

              objType.Name +

              ": "

            );


            PropertyInfo[] propInfos =

              objType.GetProperties();

            foreach (PropertyInfo propInfo in propInfos)

            {

                if (propInfo.CanWrite)

                {

                    ed.WriteMessage(

                      "\n  " +

                      propInfo.Name +

                      " : " +

                      propInfo.PropertyType

                    );

                }

            }

            ed.WriteMessage("\n");

        }

    }
}
